﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.IO;
using System.Xml.Serialization;

namespace Project
{
    /// <summary>
    /// This is the main menu
    /// </summary>
    /// 
    //lots o' stuff from http://www.alecjacobson.com/weblog/?p=539


    public class MainMenu : EngineState
    {
        Engine engine;
        ContentManager content;
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        SpriteFont statsFont;
        private Song currentSong;

        //mouse pressed and mouse just pressed
        bool mpressed, prev_mpressed = false;
        //mouse location in window
        int mx, my;
        double frame_time;

        enum BState
        {
            HOVER,
            UP,
            JUST_RELEASED,
            DOWN
        }
        const int NUMBER_OF_BUTTONS = 4,
            START_BUTTON_INDEX = 0,
            HELP_BUTTON_INDEX = 1,
            HIGHSCORE_BUTTON_INDEX = 2,
            EXIT_BUTTON_INDEX = 3,
            BUTTON_HEIGHT = 64,
            BUTTON_WIDTH = 512;
        Color background_color;
        Color[] button_color = new Color[NUMBER_OF_BUTTONS];
        Rectangle[] button_rectangle = new Rectangle[NUMBER_OF_BUTTONS];
        BState[] button_state = new BState[NUMBER_OF_BUTTONS];
        Texture2D[] button_texture = new Texture2D[NUMBER_OF_BUTTONS];
        Texture2D[] button_hover_texture = new Texture2D[NUMBER_OF_BUTTONS];
        double[] button_timer = new double[NUMBER_OF_BUTTONS];

        Texture2D logo, copyright;


        public void initialize(Engine e, ContentManager cm, GraphicsDeviceManager gdm)
        {
            engine = e;
            content = cm;
            graphics = gdm;

            createHighScoreFile();

            Vector2 viewportSize = new Vector2(graphics.GraphicsDevice.Viewport.Width,
                graphics.GraphicsDevice.Viewport.Height);
            // starting x and y locations to stack buttons
            // vertically in the middle of the screen
            int x = graphics.GraphicsDevice.Viewport.Width / 2 - BUTTON_WIDTH / 2;
            int y = graphics.GraphicsDevice.Viewport.Height / 2 -
                NUMBER_OF_BUTTONS / 2 * BUTTON_HEIGHT -
                (NUMBER_OF_BUTTONS % 2) * BUTTON_HEIGHT / 2 + 20;
            for (int i = 0; i < NUMBER_OF_BUTTONS; i++)
            {
                button_state[i] = BState.UP;
                button_color[i] = Color.White;
                button_timer[i] = 0.0;
                button_rectangle[i] = new Rectangle(x, y, BUTTON_WIDTH, BUTTON_HEIGHT);
                y += BUTTON_HEIGHT + 4;
            }
            engine.setMouseVisible(true);
            background_color = new Color(30, 30, 30);
        }

        public void destroy()
        {
        }

        public void loadContent()
        {
            spriteBatch = new SpriteBatch(graphics.GraphicsDevice);
            statsFont = content.Load<SpriteFont>("fonts/Arial");
            button_texture[START_BUTTON_INDEX] =
               content.Load<Texture2D>(@"images/start");
            button_texture[HELP_BUTTON_INDEX] =
               content.Load<Texture2D>(@"images/help");
            button_texture[HIGHSCORE_BUTTON_INDEX] =
               content.Load<Texture2D>(@"images/highscores");
            button_texture[EXIT_BUTTON_INDEX] =
                content.Load<Texture2D>(@"images/exit");

            button_hover_texture[START_BUTTON_INDEX] =
                content.Load<Texture2D>(@"images/start_selected");
            button_hover_texture[HELP_BUTTON_INDEX] =
               content.Load<Texture2D>(@"images/help_selected");
            button_hover_texture[HIGHSCORE_BUTTON_INDEX] =
               content.Load<Texture2D>(@"images/highscores_selected");
            button_hover_texture[EXIT_BUTTON_INDEX] =
                content.Load<Texture2D>(@"images/exit_selected");

            logo = content.Load<Texture2D>(@"images/title");
            copyright = content.Load<Texture2D>(@"images/copyright");
        }

        public void update(GameTime gameTime)
        {
            if ((Keyboard.GetState().IsKeyDown(Keys.Escape)))
                engine.exit();
            else
            {
                // get elapsed frame time in seconds
                frame_time = gameTime.ElapsedGameTime.Milliseconds / 1000.0;

                // update mouse variables
                MouseState mouse_state = Mouse.GetState();
                mx = mouse_state.X;
                my = mouse_state.Y;
                prev_mpressed = mpressed;
                mpressed = mouse_state.LeftButton == ButtonState.Pressed;
            }
            update_buttons();
        }

        public void draw(GameTime gameTime)
        {

            graphics.GraphicsDevice.Clear(background_color);

            spriteBatch.Begin();

            spriteBatch.Draw(logo, new Rectangle(80, 20, 647, 84), Color.White);
            spriteBatch.Draw(copyright, new Rectangle(60, 440, 702, 36), Color.White);

            for (int i = 0; i < NUMBER_OF_BUTTONS; i++)
            {
                if (button_state[i] == BState.UP)
                    spriteBatch.Draw(button_texture[i], button_rectangle[i], button_color[i]);
                else
                    spriteBatch.Draw(button_hover_texture[i], button_rectangle[i], button_color[i]);
            }
            spriteBatch.End();
            /*
            base.Draw(gameTime);

            float xOffsetText, yOffsetText;
            Vector2 viewportSize = new Vector2(graphics.GraphicsDevice.Viewport.Width,
                graphics.GraphicsDevice.Viewport.Height);
            Vector2 strCenter;

            graphics.GraphicsDevice.Clear(Color.SteelBlue);

            xOffsetText = yOffsetText = 0;
            String str1 = "Team Psyduck aka Probopass";
            Vector2 strInstructionsSize =
                statsFont.MeasureString(str1);
            Vector2 strPosition;
            strCenter = new Vector2(strInstructionsSize.X / 2,
                strInstructionsSize.Y / 2);

            yOffsetText = (viewportSize.Y / 2 - strCenter.Y);
            xOffsetText = (viewportSize.X / 2 - strCenter.X);
            strPosition = new Vector2((int)xOffsetText, (int)yOffsetText);

            spriteBatch.Begin();
            spriteBatch.DrawString(statsFont, str1,
                strPosition, Color.White);


            String str2 = "Control with WASD and the Arrow Keys, press ENTER to continue";
            strInstructionsSize =
                statsFont.MeasureString(str2);
            strCenter = new Vector2(strInstructionsSize.X / 2,
                strInstructionsSize.Y / 2);
            yOffsetText =
                (viewportSize.Y / 2 - strCenter.Y) + statsFont.LineSpacing;
            xOffsetText = (viewportSize.X / 2 - strCenter.X);
            strPosition = new Vector2((int)xOffsetText, (int)yOffsetText);

            spriteBatch.DrawString(statsFont, str2,
                strPosition, Color.LightGray);

            spriteBatch.End();

            //re-enable depth buffer after sprite batch disablement

            DepthStencilState dss = new DepthStencilState();
            dss.DepthBufferEnable = true;
            graphics.GraphicsDevice.DepthStencilState = dss;
             * 
             */
        }

        // wrapper for hit_image_alpha taking Rectangle and Texture
        Boolean hit_image_alpha(Rectangle rect, Texture2D tex, int x, int y)
        {
            return hit_image_alpha(0, 0, tex, tex.Width * (x - rect.X) /
                rect.Width, tex.Height * (y - rect.Y) / rect.Height);
        }

        // wraps hit_image then determines if hit a transparent part of image
        Boolean hit_image_alpha(float tx, float ty, Texture2D tex, int x, int y)
        {
            if (hit_image(tx, ty, tex, x, y))
            {
                uint[] data = new uint[tex.Width * tex.Height];
                tex.GetData<uint>(data);
                if ((x - (int)tx) + (y - (int)ty) *
                    tex.Width < tex.Width * tex.Height)
                {
                    return ((data[
                        (x - (int)tx) + (y - (int)ty) * tex.Width
                        ] &
                                0xFF000000) >> 24) > 20;
                }
            }
            return false;
        }

        // determine if x,y is within rectangle formed by texture located at tx,ty
        Boolean hit_image(float tx, float ty, Texture2D tex, int x, int y)
        {
            return (x >= tx &&
                x <= tx + tex.Width &&
                y >= ty &&
                y <= ty + tex.Height);
        }

        // determine state and color of button
        void update_buttons()
        {
            for (int i = 0; i < NUMBER_OF_BUTTONS; i++)
            {

                if (hit_image_alpha(
                    button_rectangle[i], button_texture[i], mx, my))
                {
                    //button_texture[i] = button_hover_texture[i];
                    button_timer[i] = 0.0;
                    if (mpressed)
                    {
                        // mouse is currently down
                        button_state[i] = BState.DOWN;
                        //button_color[i] = Color.Blue;
                    }
                    else if (!mpressed && prev_mpressed)
                    {
                        // mouse was just released
                        if (button_state[i] == BState.DOWN)
                        {
                            // button i was just down
                            button_state[i] = BState.JUST_RELEASED;
                        }
                    }
                    else
                    {
                        button_state[i] = BState.HOVER;
                        //button_color[i] = Color.LightBlue;
                    }
                }
                else
                {
                    button_state[i] = BState.UP;
                    if (button_timer[i] > 0)
                    {
                        button_timer[i] = button_timer[i] - frame_time;
                    }
                    else
                    {
                        button_color[i] = Color.White;
                    }
                }

                if (button_state[i] == BState.JUST_RELEASED)
                {
                    take_action_on_button(i);
                }
            }
        }

        // Logic for each button click goes here
        void take_action_on_button(int i)
        {
            //take action corresponding to which button was clicked
            switch (i)
            {
                case START_BUTTON_INDEX:
                    engine.setState(new LevelSelect());
                    //engine.setState(new Game());
                    break;
                case HELP_BUTTON_INDEX:
                    engine.setState(new Help());
                    break;
                case HIGHSCORE_BUTTON_INDEX:
                    engine.setState(new HighScores());
                    break;
                case EXIT_BUTTON_INDEX:
                    engine.exit();
                    break;
                default:
                    break;
            }

        }

        private void createHighScoreFile()
        {
            if (!File.Exists("highscores.lst"))
            {
                FileStream stream = File.Open("highscores.lst", FileMode.OpenOrCreate);
                int[] data = { 4000, 4000, 4000, 4000 };
                try
                {
                    // Convert the object to XML data and put it in the stream
                    XmlSerializer serializer = new XmlSerializer(typeof(int[]));
                    serializer.Serialize(stream, data);
                }
                finally
                {
                    // Close the file
                    stream.Close();
                }
            }
        }

    }
}
